home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The X-Philes (2nd Revision)
/
The X-Philes Number 1 (1995).iso
/
xphiles
/
hp95
/
freyja13.exe
/
lha
/
CALC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-22
|
55KB
|
2,380 lines
/* CALC.C -- RPN Calculator
Written March 1991 by Craig A. Finseth
Copyright 1991 by Craig A. Finseth
*/
#include "freyja.h"
#include <math.h>
#if defined(MSDOS)
#include <time.h>
#endif
/* ---------- configuration ---------- */
#define REGCOUNT 32 /* number of user registers */
#define BINSIZE 32 /* max size of a binary in bits */
#define WORKSIZE 20 /* amount of "working input" space */
#define SYS_ALPHA "%alpha%"
#define SYS_CALC "%calc%"
#define SYS_PRINT "%print%"
#define SYS_TRACE "%trace%"
/* ---------- commands ---------- */
enum CMDS { CM_ABS, CM_ACOS, CM_ADD, CM_AND, CM_ASIN, CM_ATAN, CM_B,
CM_CF, CM_CLRG, CM_CLST, CM_CLSUM, CM_CLX, CM_COS, CM_D, CM_DATE,
CM_DATEM, CM_DATEP, CM_DDAYS, CM_DEC, CM_DEFAULT, CM_DEG,
CM_DIGSEPOFF, CM_DIGSEPON, CM_DIV, CM_DMY, CM_DOW, CM_DTOR, CM_ENTER,
CM_EXP, CM_EXPM1, CM_FACT, CM_FRC, CM_GRAD, CM_H, CM_HELP, CM_HMS,
CM_HMSM, CM_HMSP, CM_HR, CM_INT, CM_INV, CM_LASTX, CM_LN, CM_LNP1,
CM_LOG, CM_MDY, CM_MEAN, CM_MEMLOAD, CM_MEMSAVE, CM_MEMSUM,
CM_MEMVIEW, CM_MOD, CM_MUL, CM_NEG, CM_NOT, CM_NULL, CM_NUM, CM_O,
CM_OCT, CM_OR, CM_PCT, CM_PCTCH, CM_PCTTOT, CM_PI, CM_PTOR, CM_PWR,
CM_RAD, CM_RADIXC, CM_RADIXD, CM_RCL, CM_RDN, CM_RTOD, CM_RTOP,
CM_RUP, CM_SDEV, CM_SF, CM_SIGN, CM_SIN, CM_SQ, CM_SQRT, CM_STD,
CM_STO, CM_SUB, CM_SUMADD, CM_SUMGET, CM_SUMSET, CM_SUMSUB, CM_SWAP,
CM_SWAPR, CM_TAN, CM_TENX, CM_TIME, CM_TRACEOFF, CM_TRACEON, CM_WSIZE,
CM_WSIZEQ, CM_X360, CM_X365, CM_XACTUAL, CM_XCAL, CM_XCALD, CM_XEQ,
CM_XOR, CM_XRND, CM_XROOT, CM_LAST };
/* ---------- command list ---------- */
struct command {
enum CMDS cmd; /* command id */
char *name; /* command name */
char desc[11]; /* command descriptor:
desc[0], command suffix
SP none
'B' buffer name
'L' label
'N' number
'P' oPerator or register
'R' register
desc[1], number of arguments dropped off the stack
'0' zero, '1', one, '2' two, '3' three, '4' four
desc[2345], argument descriptors
SP no argument for this entry
'*' any type
'B' coerce to binary
'R' coerce to real
desc[6], number of results pushed to stack
'0' zero, '1', one, '2' two, '3' three, '4' four
desc[7], last X usage
SP not affected
'L' last x register is updated
desc[8], stack lift
SP disabled
'E' enabled
desc[9], trace info
SP nothing special
R register
S summation
desc[10] NUL */
char *help; /* help string */
};
#define NUMCMDS (sizeof(commands) / sizeof(commands[0]))
/* base commands */
static struct command commands[] = {
{ CM_NUM, "", " 0 1 E ", "enter a number" },
{ CM_PCT, "%", " 2RR 2LE ", "percent" },
{ CM_PCTCH, "%CH", " 2RR 1LE ", "percent change" },
{ CM_PCTTOT, "%TOT", " 2RR 2LE ", "percent of total" },
{ CM_MUL, "*", " 2** 1LE ", "multiply" },
{ CM_ADD, "+", " 2** 1LE ", "add" },
{ CM_SUB, "-", " 2** 1LE ", "subtract" },
{ CM_DIV, "/", " 2RR 1LE ", "divide" },
{ CM_INV, "1/X", " 1R 1LE ", "inverse (use INV)" },
{ CM_TENX, "10^X", " 2RR 1LE ", "common exponent (use ALOG)" },
{ CM_RCL, "<", "P0 1 ER", "recall" },
{ CM_STO, ">", "P1* 1 ER", "store" },
{ CM_ABS, "ABS", " 1R 1LE ", "absolute value" },
{ CM_ACOS, "ACOS", " 1R 1LE ", "arc cosine" },
{ CM_TENX, "ALOG", " 2RR 1LE ", "common exponent" },
{ CM_AND, "AND", " 2BB 1LE ", "bitwise and" },
{ CM_ASIN, "ASIN", " 1R 1LE ", "arc sin" },
{ CM_ATAN, "ATAN", " 1R 1LE ", "arc tangenet" },
{ CM_B, "B", " 0 0 E ", "set binary mode" },
{ CM_CF, "CF", "N0 0 E ", "clear flag" },
{ CM_CLRG, "CLRG", " 0 0 E ", "clear registers" },
{ CM_CLST, "CLST", " 0 0 E ", "clear stack" },
{ CM_CLX, "CLX", " 0 0 D ", "clear x" },
{ CM_CLSUM, "CL\\GS"," 0 0 ES", "clear summation" },
{ CM_CLSUM, "CL~", " 0 0 ES", "clear summation" },
{ CM_COS, "COS", " 1R 1LE ", "cosine" },
{ CM_D, "D", " 0 0 E ", "set decimal mode" },
{ CM_DTOR, "D-R", " 1R 1LE ", "convert degrees to radians" },
{ CM_DATEM, "DATE-"," 2BR 1LE ", "subtract days from date" },
{ CM_DATEP, "DATE+"," 2BR 1LE ", "add days to date" },
{ CM_DATE, "DATE", " 0 1 E ", "return the current date" },
{ CM_DDAYS, "DDAYS"," 2RR 1LE ", "compute days between dates" },
{ CM_DEC, "DEC", " 1* 1LE ", "convert octal to decimal" },
{ CM_DEFAULT, "DEFAULT"," 0 0 E ", "restore default settings" },
{ CM_DEG, "DEG", " 0 0 E ", "set degrees mode" },
{ CM_DIGSEPOFF, "DIGSEPOFF"," 0 0 E ","set digit sep to not display" },
{ CM_DIGSEPON, "DIGSEPON"," 0 0 E ","set digit sep to display" },
{ CM_DOW, "DOW", " 1R 1 E ", "figure a date's day of the week" },
{ CM_DMY, "DMY", " 0 0 E ", "set D.MY mode" },
{ CM_ENTER, "ENTER^"," 1* 2 D ", "enter" },
{ CM_EXP, "E^X", " 1R 1LE ", "natural exponent" },
{ CM_EXPM1, "E^X-1"," 1R 1LE ", "natural exponent - 1" },
{ CM_FACT, "FACT", " 1R 1LE ", "factorial" },
{ CM_FRC, "FRC", " 1R 1LE ", "fractional part" },
{ CM_GRAD, "GRAD", " 0 0 E ", "set grads mode" },
{ CM_H, "H", " 0 0 E ", "set hexadecimal mode" },
{ CM_HELP, "HELP", " 0 0 E ", "help" },
{ CM_HMSM, "HMS-", " 2RR 1LE ", "subtract two times in H.MS notation"},
{ CM_HMSP, "HMS+", " 2RR 1LE ", "add two times in H.MS notation" },
{ CM_HMS, "HMS", " 1R 1LE ", "convert decimal hours to H.MS" },
{ CM_HR, "HR", " 1R 1LE ", "convert H.MS to decimal hours" },
{ CM_INT, "INT", " 1R 1LE ", "integer part" },
{ CM_INV, "INV", " 1R 1LE ", "inverse" },
{ CM_LASTX, "L", " 0 1 E ", "recall last x" },
{ CM_LASTX, "LASTX"," 0 1 E ", "recall last x" },
{ CM_LN, "LN", " 1R 1LE ", "natural logarithm" },
{ CM_LNP1, "LN1+X"," 1R 1LE ", "natural logarithm + 1" },
{ CM_LOG, "LOG", " 1R 1LE ", "common logarithm" },
{ CM_MDY, "MDY", " 0 0 E ", "set M.DY mode" },
{ CM_MEAN, "MEAN", " 0 2 ES", "average" },
{ CM_MEMLOAD, "MEMLOAD"," 0 0 E ", "load calculator memory" },
{ CM_MEMSAVE, "MEMSAVE"," 0 0 E ", "save calculator memory" },
{ CM_MEMVIEW, "MEMVIEW"," 0 0 E ", "view calculator memory" },
{ CM_MEMSUM, "MEM\\GS"," 0 0 E ", "view summation registers" },
{ CM_MEMSUM, "MEM~", " 0 0 E ", "view summation registers" },
{ CM_MOD, "MOD", " 2RR 1LE ", "modulus" },
{ CM_NEG, "NEG", " 1R 1LE ", "negate" },
{ CM_NOT, "NOT", " 1B 1LE ", "bitwise not" },
{ CM_NULL, "NULL", " 0 0 E ", "no op" },
{ CM_O, "O", " 0 0 E ", "set octal mode" },
{ CM_OCT, "OCT", " 1* 1LE ", "convert decimal to octal" },
{ CM_OR, "OR", " 2BB 1LE ", "bitwise or" },
{ CM_PTOR, "P-R", " 2RR 2LE ", "convert polar to rectangular" },
{ CM_PI, "PI", " 0 1 E ", "constant pi" },
{ CM_RDN, "R", " 0 0 E ", "roll down" },
{ CM_RTOD, "R-D", " 1R 1LE ", "convert radians to degrees" },
{ CM_RTOP, "R-P", " 2RR 2LE ", "convert rectangular to polar" },
{ CM_RAD, "RAD", " 0 0 E ", "set radians mode" },
{ CM_RADIXC, "RADIX,"," 0 0 E ", "set radix mark to ," },
{ CM_RADIXD, "RADIX."," 0 0 E ", "set radix mark to ." },
{ CM_RCL, "RCL", "P0 1 ER", "recall" },
{ CM_RDN, "RDN", " 0 0 E ", "roll down" },
{ CM_RUP, "R^", " 0 0 E ", "roll up" },
{ CM_SWAP, "S", " 2** 2 E ", "swap: x<>y" },
{ CM_SDEV, "SDEV", " 0 2 ES", "standard deviation" },
{ CM_SIGN, "SIGN", " 1R 1LE ", "sign of number" },
{ CM_SIN, "SIN", " 1R 1LE ", "sin" },
{ CM_SF, "SF", "N0 0 E ", "set flag" },
{ CM_SQRT, "SQRT", " 1R 1LE ", "square root" },
{ CM_STD, "STD", " 0 0 E ", "set display all digits notation" },
{ CM_STO, "STO", "P1* 1 ER", "store" },
{ CM_STO, "ST", "P1* 1 ER", "store" },
{ CM_ENTER, "T", " 1* 2 D ", "enter" },
{ CM_TAN, "TAN", " 1R 1LE ", "tangent" },
{ CM_TIME, "TIME", " 0 1 E ", "return the current time" },
{ CM_TRACEOFF, "TRACEOFF"," 0 0 E ","set trace mode off" },
{ CM_TRACEON, "TRACEON"," 0 0 E ", "set trace mode on" },
{ CM_WSIZE, "WSIZE"," 1B 0 E ", "set word size" },
{ CM_WSIZEQ, "WSIZE?"," 0 1 E ", "get word size" },
{ CM_X360, "X360", " 0 0 E ", "set mode to 360 day calendar" },
{ CM_X365, "X365", " 0 0 E ", "set mode to 365 day calendar" },
{ CM_SWAPR, "X<>", "R1* 1 ER", "swap with" },
{ CM_XACTUAL, "XACTUAL"," 0 0 E ", "set mode to actual calendar" },
{ CM_XCAL, "XCAL", " 1R 0LE ", "generate a calendar for the date" },
{ CM_XCALD, "XCALD"," 1B 0LE ", "move the calendar by X months" },
{ CM_XEQ, "XEQ", "B0 0 E ", "execute a buffer" },
{ CM_XOR, "XOR", " 2BB 1LE ", "bitwise xor" },
{ CM_XRND, "XRND", " 2BR 1LE ", "round Y to X decimal places" },
{ CM_XROOT, "XROOT"," 2RR 1LE ", "xth root of y" },
{ CM_SQ, "X^2", " 1* 1LE ", "square" },
{ CM_PWR, "Y^X", " 2RR 1LE ", "exponentiation" },
{ CM_PCTCH, "\\GD%"," 2RR 1LE ", "delta %" },
{ CM_SUMADD, "\\GS+"," 2RR 2LDS", "summation plus" },
{ CM_SUMSUB, "\\GS-"," 2RR 2LDS", "summation minus" },
{ CM_SUMGET, "\\GSREG?"," 0 1 E ","get summation register" },
{ CM_SUMSET, "\\GSREG","R1B 0 ER", "set summation register" },
{ CM_PWR, "^", " 2RR 1LE ", "exponentiation" },
{ CM_SUMADD, "~+", " 2RR 2LDS", "summation plus" },
{ CM_SUMSUB, "~-", " 2RR 2LDS", "summation minus" },
{ CM_SUMGET, "~REG?"," 0 1 E ", "get summation register" },
{ CM_SUMSET, "~REG", "R1B 0 ER", "set summation register" } };
/* ---------- flags ---------- */
/* The flag array (part of memory) assumes 16 flags/int. That way,
the indices in this table don't have to be recomputed for different
word sizes. */
enum FLGS { FL_AUTO, FL_PRTDBL, FL_PRTLWR, FL_CRDOVER, FL_ILPRT,
FL_RECINC, FL_INTENA, FL_PRTENA, FL_NUMINP, FL_ALPINP, FL_IGNRANGE,
FL_IGNERROR, FL_AUDIO, FL_USER, FL_RADIX, FL_DIGGRP, FL_CATALOG,
FL_DMYDATE, FL_MANIO, FL_ABSMAN, FL_AUTOADD, FL_AUTOST, FL_DIGITS,
FL_DISPFMT, FL_TRIGMODE, FL_CONTON, FL_SYSDATA, FL_PARTIAL, FL_SHIFT,
FL_ALPHA, FL_LOWBAT, FL_SST, FL_PRGM, FL_IOREQ, FL_PSE, FL_MSG,
FL_PRTEX, FL_WSIZE, FL_BINMODE, FL_CMPMODE, FL_CALMODE, FL_SUMBASE,
FL_UPPREQ, FL_NOLNUMS, FL_LIMALPHA, FL_LIMFNAME, FL_LAST };
struct flag {
enum FLGS flg; /* flag id */
int start; /* starting flag # */
int bits; /* number of bits */
int index; /* flag array index */
int shift; /* flag array element shift */
int mask; /* flag array element mask */
char *desc; /* description */
};
#define NUMFLAGS 7 /* number of ints used to hold flags */
#define MAXFLAG 100 /* largest flag supported */
struct flag flags[] = { /* must be in enum FLGS order */
/* user flags */
{ FL_AUTO, 11, 1, 0, 11, 0x1, "auto execution (NS)" },
{ FL_PRTDBL, 12, 1, 0, 12, 0x1, "print double wide (NS)" },
{ FL_PRTLWR, 13, 1, 0, 13, 0x1, "print lower case" },
{ FL_CRDOVER, 14, 1, 0, 14, 0x1, "card reader allow overwrite (NS)" },
{ FL_ILPRT, 15, 2, 0, 15, 0x3,
"HPIL printer: 0)manual 1)normal 2)trace 3)trace w/stack print" },
{ FL_RECINC, 17, 1, 1, 1, 0x1, "record incomplete" },
{ FL_INTENA, 18, 1, 1, 2, 0x1, "IL interrupt enable (NS)" },
{ FL_PRTENA, 21, 1, 1, 5, 0x1, "printer enabled" },
{ FL_NUMINP, 22, 1, 1, 6, 0x1, "numeric input available" },
{ FL_ALPINP, 23, 1, 1, 7, 0x1, "alpha input available" },
{ FL_IGNRANGE, 24, 1, 1, 8, 0x1, "ignore range errors (NS)" },
{ FL_IGNERROR, 25, 1, 1, 9, 0x1, "ignore any errors & clear" },
{ FL_AUDIO, 26, 1, 1, 10, 0x1, "audio I/O is ignored" },
{ FL_USER, 27, 1, 1, 11, 0x1, "user mode is active (NS)" },
{ FL_RADIX, 28, 1, 1, 12, 0x1, "radix mark: 0). 1)," },
{ FL_DIGGRP, 29, 1, 1, 13, 0x1, "digit groupings shown: 0)no 1)yes" },
{ FL_CATALOG, 30, 1, 1, 14, 0x1, "catalog set (NS)" },
{ FL_DMYDATE, 31, 1, 1, 15, 0x1, "date mode: 0)M.DY 1)D.MY" },
/* system flags */
{ FL_MANIO, 32, 1, 2, 0, 0x1, "IL man I/O mode (NS)" },
{ FL_ABSMAN, 33, 1, 2, 1, 0x1, "can control IL (NS)" },
{ FL_AUTOADD, 34, 1, 2, 2, 0x1, "prevent IL auto address (NS)" },
{ FL_AUTOST, 35, 1, 2, 3, 0x1, "disable auto start (NS)" },
{ FL_DIGITS, 36, 4, 2, 4, 0xF, "number of digits, 0-15" },
{ FL_DISPFMT, 40, 2, 2, 8, 0x3,
"display format: 0)sci 1)eng 2)fix 3)std (41:really fix/eng mode)" },
#define FLV_SCI 0x00
#define FLV_ENG 0x01
#define FLV_FIX 0x02
#define FLV_STD 0x03
{ FL_TRIGMODE, 42, 2, 2, 10, 0x3,
"angle mode: 0)deg 1)rad 2)grad 3)rad (don't use)" },
#define FLV_DEG 0x00
#define FLV_RAD 0x01
#define FLV_GRD 0x02
#define FLV_RAD2 0x03
{ FL_CONTON, 44, 1, 2, 12, 0x1, "continuous on (NS)" },
{ FL_SYSDATA, 45, 1, 2, 13, 0x1, "system data entry" },
{ FL_PARTIAL, 46, 1, 2, 14, 0x1, "partial key sequence (NS)" },
{ FL_SHIFT, 47, 1, 2, 15, 0x1, "shift key pressed (NS)" },
{ FL_ALPHA, 48, 1, 3, 0, 0x1, "alpha keyboard active (NS)" },
{ FL_LOWBAT, 49, 1, 3, 1, 0x1, "low battery (NS)" },
{ FL_MSG, 50, 1, 3, 2, 0x1, "set when a message is displayed (NS)" },
{ FL_SST, 51, 1, 3, 3, 0x1, "single step mode (NS)" },
{ FL_PRGM, 52, 1, 3, 4, 0x1, "program mode (NS)" },
{ FL_IOREQ, 53, 1, 3, 5, 0x1, "IL I/O request (NS)" },
{ FL_PSE, 54, 1, 3, 6, 0x1, "set during pause (NS)" },
{ FL_PRTEX, 55, 1, 3, 7, 0x1, "printer exists" },
/* Freyja-local flags */
{ FL_WSIZE, 65, 8, 4, 0,0xFF, "binary integer word size" },
{ FL_BINMODE, 73, 2, 4, 8, 0x3, "binary numbers 0)dec 1)oct 2)bin 3)hex" },
#define FLV_DEC 0x00
#define FLV_OCT 0x01
#define FLV_BIN 0x02
#define FLV_HEX 0x03
{ FL_CMPMODE, 75, 2, 4, 10, 0x3,
"complement mode: 0)uns 1)1's 2)2's 3)uns (don't use)" },
#define FLV_UNS 0x00
#define FLV_1S 0x01
#define FLV_2S 0x02
#define FLV_UNS2 0x03
{ FL_CALMODE, 77, 2, 4, 12, 0x3,
"calendar mode: 0)360 1)actual 2)365 3)actual (don't use)" },
#define FLV_360 0x00
#define FLV_ACT 0x01
#define FLV_365 0x02
#define FLV_ACT2 0x03
{ FL_SUMBASE, 81,16, 5, 0,0xFFFF, "summation base register" },
{ FL_UPPREQ, 97, 1, 6, 0, 0x1, "commands must be upper case" },
{ FL_NOLNUMS, 98, 1, 6, 1, 0x1, "no line numbers are present" },
{ FL_LIMALPHA, 99, 1, 6, 2, 0x1, "alpha register limited to 24 chars" },
{ FL_LIMFNAME, 100, 1, 6, 3, 0x1, "file names limited to 7 characters" } };
/* ---------- number format ---------- */
struct number {
union {
int b; /* binary integer goes here */
double r; /* real number goes here */
} n;
char type; /* 'B' binary, 'R' real */
};
/* ---------- memory ---------- */
#define NUMSTACK 5
#define NUMREGS (REGCOUNT + NUMSTACK)
#define X (NUMREGS)
#define Y (NUMREGS + 1)
#define Z (NUMREGS + 2)
#define T (NUMREGS + 3)
#define L (NUMREGS + 4)
#define NUMSUM 6
#define SUMX 0
#define SUMX2 1
#define SUMY 2
#define SUMY2 3
#define SUMXY 4
#define SUMN 5
static struct memory {
struct number r[NUMREGS + NUMSTACK];
int flags[NUMFLAGS]; /* the flags */
FLAG trace_mode; /* is tracing on? */
FLAG stack_lift;
};
/* ---------- constants ---------- */
#define PI 3.1415926535
/* ---------- variables ---------- */
static struct memory m; /* memory */
static char fname[FNAMEMAX] = { NUL }; /* memory filename */
static char input[WORKSIZE + 1]; /* buffer for holding input */
static char fmt_buf[BINSIZE + 2]; /* buffer for U_Fmt */
static int bin_mask; /* word mask for binary operations */
static char exit = NUL; /* do we exit? NUL = no, N = yes,
don't insert #, Y = yes, insert # */
static enum CMDS pushedcmd = CM_NULL; /* pushed command: execute first */
static struct command *cmdptr; /* current command */
static int cmdnum; /* numeric argument for command */
static FLAG cmdind; /* was it an indirect? */
static struct number *cmdreg; /* register pointer */
static enum CMDS cmdcmd; /* command for sto/rcl */
static char *cmdrest; /* rest of command string */
/* Arguments for commands. Values have been coerced. */
static struct number x;
static struct number y;
static struct number z;
static struct number t;
void U_Cmd(); /* void */
void U_CmdSetup(); /* char arg, struct number *from,
struct number *to */
char *U_Dispatch(); /* enum CMDS cmd */
struct command *U_FindCmd(); /* enum CMDS cmd */
int U_FlGet(); /* enum FLGS f */
void U_FlSet(); /* enum FLGS f, int value */
char *U_Fmt(); /* struct number *nptr */
char *U_FmtBin(); /* char *buf, int value, FLAG first */
void U_FromTrig(); /* struct number *nptr */
double U_HMSAdd(); /* double hms1, double hms2 */
FLAG U_In(); /* void */
void U_Load(); /* void */
void U_Save(); /* void */
void U_Status(); /* void */
void U_ToBin(); /* struct number *nptr */
double U_ToDate(); /* struct tm *tptr */
double U_ToHMS(); /* double hr */
double U_ToHR(); /* double hms */
void U_ToReal(); /* struct number *nptr */
void U_ToTM(); /* struct tm *tptr, double date */
void U_ToTrig(); /* struct number *nptr */
void U_Trace1(); /* void */
void U_Trace2(); /* char *retval */
void U_View(); /* void */
void U_ViewSum(); /* void */
/* ------------------------------------------------------------ */
/* Initialize to default values. */
void
UInit()
{
int cnt;
for (cnt = 0; cnt < NUMREGS; cnt++) {
m.r[cnt].type = 'R';
m.r[cnt].n.r = 0.0;
}
for (cnt = 0; cnt < NUMFLAGS; cnt++) {
m.flags[cnt] = 0;
}
U_FlSet(FL_RADIX, 1);
U_FlSet(FL_DIGGRP, 1);
U_FlSet(FL_DIGITS, 4);
U_FlSet(FL_DISPFMT, FLV_STD);
U_FlSet(FL_WSIZE, BINSIZE);
bin_mask = ~0;
U_FlSet(FL_BINMODE, FLV_HEX);
U_FlSet(FL_CALMODE, FLV_ACT);
U_FlSet(FL_SUMBASE, 11);
m.trace_mode = FALSE;
m.stack_lift = TRUE;
}
/* ------------------------------------------------------------ */
/* Calculator */
void
UCalc()
{
uarg = 0;
for (exit = NUL; exit == NUL; ) {
U_In();
if (cmdptr != NULL) U_Cmd();
}
if (exit == 'Y') BInsStr(U_Fmt(&m.r[X]));
DModeLine();
}
/* ------------------------------------------------------------ */
/* Return the operation's description. */
char *
UDescr(op)
int op;
{
return(commands[op].name);
}
/* ------------------------------------------------------------ */
/* Enter the current number into the calculator. */
void
UEnter()
{
char buf[WORKSIZE + 1];
FLAG isafter;
FLAG isfirst = TRUE;
char *cptr = buf;
int chr;
WNumMark();
if (isafter = BIsAfterMark(mark)) BMarkSwap(mark);
BMarkToPoint(cwin->point);
while (cptr < &buf[sizeof(buf) - 2] && BIsBeforeMark(mark)) {
chr = BGetCharAdv();
if (isfirst) {
if (chr == '-') *cptr++ = '0';
isfirst = FALSE;
}
if (chr == '-') chr = '~';
*cptr++ = chr;
}
*cptr++ = SP;
BPointToMark(cwin->point);
if (isafter) BMarkSwap(mark);
uarg = 0;
KFromStr(buf, cptr - buf);
UCalc();
}
/* ------------------------------------------------------------ */
/* Return the operation's help text. */
char *
UHelp(op)
int op;
{
return(commands[op].help);
}
/* ------------------------------------------------------------ */
/* Load and save the keyboard macro buffer. */
void
ULoadMac()
{
int cnt;
int *iptr = KMacPtr();
if (isuarg) { /* load */
BMarkToPoint(cwin->point);
BMoveToStart();
for (cnt = 0; cnt < MACROMAX - 1 && !BIsEnd(); cnt++) {
*(iptr + cnt) = BGetCharAdv();
}
*(iptr + cnt) = KEYNONE;
BPointToMark(cwin->point);
}
else { /* save into buffer */
iptr = KMacPtr();
for (cnt = 0; cnt < MACROMAX && *(iptr + cnt) != KEYNONE;
cnt++) {
BInsChar(*(iptr + cnt));
}
}
uarg = 0;
}
/* ------------------------------------------------------------ */
/* Return the number of operators. */
int
UNumOps()
{
return(NUMCMDS);
}
/* ------------------------------------------------------------ */
/* Insert a copy of the X register. */
void
UPrintX()
{
uarg = 0;
if (isuarg) {
WNumMark();
RRegDelete();
}
BInsStr(U_Fmt(&m.r[X]));
}
/* ------------------------------------------------------------ */
/* Initialize the ./, and digsep on/off flags */
void
USetup(iscomma, issep)
FLAG iscomma;
FLAG issep;
{
U_FlSet(FL_RADIX, iscomma);
U_FlSet(FL_DIGGRP, issep);
}
/* ------------------------------------------------------------ */
/* Execute the current command. */
void
U_Cmd()
{
struct number tmp;
char *retval;
int amt;
/* set up args */
U_CmdSetup(cmdptr->desc[2], &m.r[X], &x);
U_CmdSetup(cmdptr->desc[3], &m.r[Y], &y);
U_CmdSetup(cmdptr->desc[4], &m.r[Z], &z);
U_CmdSetup(cmdptr->desc[5], &m.r[T], &t);
/* handle indirect registers */
if (cmdptr->desc[0] == 'R' || cmdptr->desc[0] == 'P') {
if (cmdind) {
tmp = *cmdreg;
U_ToBin(&tmp);
if (tmp.n.b < 0 || tmp.n.b >= REGCOUNT) {
DError("Unknown Indirect Register");
cmdptr = NULL;
return;
}
cmdreg = &m.r[tmp.n.b];
}
}
/* handle trace */
if (m.trace_mode) U_Trace1();
/* execute */
retval = U_Dispatch(cmdptr->cmd);
if (retval == NULL) {
/* lastx */
if (cmdptr->desc[7] == 'L') m.r[L] = m.r[X];
/* drop stack */
if (cmdptr->desc[1] == '0') {
}
else if (cmdptr->desc[1] == '1') {
m.r[X] = m.r[Y];
m.r[Y] = m.r[Z];
m.r[Z] = m.r[T];
}
else if (cmdptr->desc[1] == '2') {
m.r[X] = m.r[Z];
m.r[Y] = m.r[T];
m.r[Z] = m.r[T];
}
else {
m.r[X] = m.r[T];
m.r[Y] = m.r[T];
m.r[Z] = m.r[T];
}
/* save results */
amt = cmdptr->desc[6] - '0';
/* stack lift disabled and new operation lifts the stack */
if (!m.stack_lift && cmdptr->desc[1] < cmdptr->desc[6]) {
amt = cmdptr->desc[6] - cmdptr->desc[1] - 1;
if (amt == 0) m.r[X] = x;
}
if (amt <= 0) {
}
else if (amt == 1) {
m.r[T] = m.r[Z];
m.r[Z] = m.r[Y];
m.r[Y] = m.r[X];
m.r[X] = x;
}
else if (amt == 2) {
m.r[T] = m.r[Y];
m.r[Z] = m.r[X];
m.r[Y] = y;
m.r[X] = x;
}
else if (amt == 3) {
m.r[T] = m.r[X];
m.r[Z] = z;
m.r[Y] = y;
m.r[X] = x;
}
else {
m.r[T] = t;
m.r[Z] = z;
m.r[Y] = y;
m.r[X] = x;
}
/* stack lift */
m.stack_lift = cmdptr->desc[8] == 'E';
}
else DError(retval);
/* handle trace */
if (m.trace_mode) U_Trace2(retval);
}
/* ------------------------------------------------------------ */
/* Setup the register according to the argument type. */
void
U_CmdSetup(arg, from, to)
char arg;
struct number *from;
struct number *to;
{
if (arg != SP) {
*to = *from;
if (arg == 'B') U_ToBin(to);
else if (arg == 'R') U_ToReal(to);
}
}
/* ------------------------------------------------------------ */
/* The command dispatch table. Return NULL on success or a pointer to
an error message if a failure. */
char *
U_Dispatch(cmd)
enum CMDS cmd;
{
struct tm t;
struct number tmp;
struct number tmp2;
struct number sn;
struct number sx;
struct number sx2;
struct number sy;
struct number sy2;
struct buffer *bptr;
int cnt;
int num;
long ltmp;
char buf[WORKSIZE];
FLAG wasneg;
switch (cmd) {
case CM_ABS:
x.n.r = fabs(x.n.r);
break;
case CM_ACOS:
if (x.n.r < -1.0 || x.n.r > 1.0) return("acos <-1 or >1");
x.n.r = acos(x.n.r);
U_ToTrig(&x);
break;
case CM_ADD:
if (x.type == 'B' && y.type == 'B') {
x.n.b += y.n.b;
x.n.b &= bin_mask;
}
else {
U_ToReal(&x);
U_ToReal(&y);
x.type = 'R';
x.n.r += y.n.r;
}
break;
case CM_AND:
x.n.b &= y.n.b;
x.n.b &= bin_mask;
break;
case CM_ASIN:
if (x.n.r < -1.0 || x.n.r > 1.0) return("asin <-1 or >1");
x.n.r = asin(x.n.r);
U_ToTrig(&x);
break;
case CM_ATAN:
x.n.r = atan(x.n.r);
U_ToTrig(&x);
break;
case CM_B:
U_FlSet(FL_BINMODE, FLV_BIN);
break;
case CM_CF:
if (cmdnum < 1 || cmdnum > MAXFLAG) return("illegal flag");
num = cmdnum - 1;
m.flags[num >> 4] &= ~(1 << (num & 0xF));
break;
case CM_CLRG:
for (cnt = 0; cnt < REGCOUNT; cnt++) {
m.r[cnt].type = 'R';
m.r[cnt].n.r = 0.0;
}
break;
case CM_CLST:
for (cnt = X; cnt < L; cnt++) {
m.r[cnt].type = 'R';
m.r[cnt].n.r = 0.0;
}
break;
case CM_CLSUM:
num = U_FlGet(FL_SUMBASE);
for (cnt = num; cnt < num + NUMSUM; cnt++) {
m.r[cnt].type = 'R';
m.r[cnt].n.r = 0.0;
}
break;
case CM_CLX:
m.r[X].type = 'R';
m.r[X].n.r = 0.0;
break;
case CM_COS:
U_FromTrig(&x);
x.n.r = cos(x.n.r);
break;
case CM_D:
U_FlSet(FL_BINMODE, FLV_DEC);
break;
case CM_DATE:
DNow(&t);
x.n.r = U_ToDate(&t);
x.type = 'R';
break;
case CM_DATEM:
num = U_FlGet(FL_CALMODE);
U_ToTM(&t, y.n.r);
ltmp = DToDayN(&t, num) - x.n.b;
DToDate(&t, ltmp, num);
x.n.r = U_ToDate(&t);
x.type = 'R';
break;
case CM_DATEP:
num = U_FlGet(FL_CALMODE);
U_ToTM(&t, y.n.r);
ltmp = DToDayN(&t, num) + x.n.b;
DToDate(&t, ltmp, num);
x.n.r = U_ToDate(&t);
x.type = 'R';
break;
case CM_DDAYS:
num = U_FlGet(FL_CALMODE);
U_ToTM(&t, x.n.r);
ltmp = DToDayN(&t, num);
U_ToTM(&t, y.n.r);
x.n.r = ltmp - DToDayN(&t, num);
break;
case CM_DEC:
if (x.type == 'R' && x.n.r < 0.0) return("Negative");
U_ToBin(&x);
xsprintf(buf, "%o", x.n.b);
if (!SToN(buf, &x.n.b, 10)) return("Invalid Integer");
break;
case CM_DEFAULT:
UInit();
break;
case CM_DEG:
U_FlSet(FL_TRIGMODE, FLV_DEG);
break;
case CM_DIGSEPOFF:
U_FlSet(FL_DIGGRP, 0);
break;
case CM_DIGSEPON:
U_FlSet(FL_DIGGRP, 1);
break;
case CM_DIV:
if (x.n.r == 0.0) return("Divide by Zero");
x.n.r = y.n.r / x.n.r;
break;
case CM_DMY:
U_FlSet(FL_DMYDATE, 1);
break;
case CM_DOW:
U_ToTM(&t, x.n.r);
x.n.r = DOW(DToDayN(&t, 1));
break;
case CM_DTOR:
x.n.r *= PI / 180.0;
break;
case CM_ENTER:
y = x;
m.stack_lift = TRUE;
break;
case CM_EXP:
x.n.r = exp(x.n.r);
break;
case CM_EXPM1:
x.n.r = exp(x.n.r) - 1;
break;
case CM_FACT:
if (x.n.r < 0.0) return("Negative");
for (cnt = x.n.r, x.n.r = 1.0; cnt > 1; cnt--) {
x.n.r *= cnt;
}
break;
case CM_FRC:
wasneg = x.n.r < 0;
x.n.r = fabs(x.n.r);
x.n.r -= floor(x.n.r);
if (wasneg) x.n.r = -x.n.r;
break;
case CM_GRAD:
U_FlSet(FL_TRIGMODE, FLV_GRD);
break;
case CM_H:
U_FlSet(FL_BINMODE, FLV_HEX);
break;
case CM_HELP:
HHelp();
DIncrDisplay();
break;
case CM_HMS:
x.n.r = U_ToHMS(x.n.r);
break;
case CM_HMSM:
x.n.r = U_HMSAdd(y.n.r, -x.n.r);
break;
case CM_HMSP:
x.n.r = U_HMSAdd(y.n.r, x.n.r);
break;
case CM_HR:
x.n.r = U_ToHR(x.n.r);
break;
case CM_INT:
wasneg = x.n.r < 0;
x.n.r = fabs(x.n.r);
x.n.r = floor(x.n.r);
if (wasneg) x.n.r = -x.n.r;
break;
case CM_INV:
if (x.n.r == 0.0) return("Divide by Zero");
x.n.r = 1.0 / x.n.r;
break;
case CM_LASTX:
x = m.r[L];
break;
case CM_LN:
if (x.n.r <= 0.0) return("Negative");
x.n.r = log(x.n.r);
break;
case CM_LNP1:
if (x.n.r + 1.0 <= 0.0) return("Negative");
x.n.r = log(x.n.r + 1.0);
break;
case CM_LOG:
if (x.n.r <= 0.0) return("Negative");
x.n.r = log10(x.n.r);
break;
case CM_MDY:
U_FlSet(FL_DMYDATE, 0);
break;
case CM_MEAN:
num = U_FlGet(FL_SUMBASE);
U_ToReal(&m.r[num + SUMN]);
U_ToReal(&m.r[num + SUMX]);
U_ToReal(&m.r[num + SUMY]);
sn = m.r[num + SUMN];
sx = m.r[num + SUMX];
sy = m.r[num + SUMY];
if (sn.n.r == 0.0) return("Zero Items");
x.type = 'R';
x.n.r = sx.n.r / sn.n.r;
y.type = 'R';
y.n.r = sy.n.r / sn.n.r;
break;
case CM_MEMLOAD:
U_Load();
break;
case CM_MEMSAVE:
U_Save();
break;
case CM_MEMSUM:
U_ViewSum();
break;
case CM_MEMVIEW:
U_View();
break;
case CM_MOD:
if (x.n.r == 0.0) return("Mod of Zero");
x.n.r = y.n.r - x.n.r * floor(y.n.r / x.n.r);
break;
case CM_MUL:
if (x.type == 'B' && y.type == 'B') {
x.n.b *= y.n.b;
x.n.b &= bin_mask;
}
else {
U_ToReal(&x);
U_ToReal(&y);
x.type = 'R';
x.n.r *= y.n.r;
}
break;
case CM_NEG:
x.n.r = -x.n.r;
break;
case CM_NOT:
x.n.b = ~x.n.b;
x.n.b &= bin_mask;
break;
case CM_NULL:
break;
case CM_NUM:
break;
case CM_O:
U_FlSet(FL_BINMODE, FLV_OCT);
break;
case CM_OCT:
if (x.type == 'R' && x.n.r < 0.0) return("Negative");
U_ToBin(&x);
xsprintf(buf, "%d", x.n.b);
if (!SToN(buf, &x.n.b, 8)) return("Non-integer");
break;
case CM_OR:
x.n.b |= y.n.b;
x.n.b &= bin_mask;
break;
case CM_PCT:
x.n.r *= y.n.r / 100.0;
break;
case CM_PCTCH:
if (y.n.r == 0.0) return("Percent of Zero");
x.n.r = 100.0 * (x.n.r - y.n.r) / y.n.r;
break;
case CM_PCTTOT:
if (y.n.r == 0.0) return("Percent of Zero");
x.n.r = 100.0 * x.n.r / y.n.r;
break;
case CM_PI:
x.type = 'R';
x.n.r = PI;
break;
case CM_PTOR:
tmp.n.r = y.n.r;
U_FromTrig(&tmp);
y.n.r = x.n.r * sin(tmp.n.r);
x.n.r = x.n.r * cos(tmp.n.r);
break;
case CM_PWR:
if (y.n.r < 0.0 || (y.n.r == 0.0 && x.n.r < 0.0))
return("Negative");
x.n.r = pow(y.n.r, x.n.r);
break;
case CM_RAD:
U_FlSet(FL_TRIGMODE, FLV_RAD);
break;
case CM_RADIXC:
U_FlSet(FL_RADIX, 0);
break;
case CM_RADIXD:
U_FlSet(FL_RADIX, 1);
break;
case CM_RCL:
if (cmdnum < 0) {
for (cnt = 0; KIsKey() == 'N'; cnt++) {
xsprintf(buf, " %d ", cnt);
DEcho(buf);
}
KGetChar();
return(NULL);
}
y = x;
x = *cmdreg;
U_Dispatch(cmdcmd);
break;
case CM_RDN:
tmp = m.r[X];
m.r[X] = m.r[Y];
m.r[Y] = m.r[Z];
m.r[Z] = m.r[T];
m.r[T] = tmp;
break;
case CM_RTOD:
x.n.r *= 180.0 / PI;
break;
case CM_RTOP:
tmp.n.r = y.n.r * y.n.r;
y.n.r = atan2(y.n.r, x.n.r);
U_ToTrig(&y);
x.n.r = sqrt(x.n.r * x.n.r + tmp.n.r);
break;
case CM_RUP:
tmp = m.r[X];
m.r[X] = m.r[T];
m.r[T] = m.r[Z];
m.r[Z] = m.r[Y];
m.r[Y] = tmp;
break;
case CM_SDEV:
num = U_FlGet(FL_SUMBASE);
U_ToReal(&m.r[num + SUMN]);
U_ToReal(&m.r[num + SUMX]);
U_ToReal(&m.r[num + SUMX2]);
U_ToReal(&m.r[num + SUMY]);
U_ToReal(&m.r[num + SUMY2]);
sn = m.r[num + SUMN];
sx = m.r[num + SUMX];
sx2 = m.r[num + SUMX2];
sy = m.r[num + SUMY];
sy2 = m.r[num + SUMY2];
tmp.n.r = sn.n.r * (sn.n.r - 1.0);
if (tmp.n.r == 0.0) return("Zero Items");
tmp2.n.r = (sn.n.r * sx2.n.r - sx.n.r * sx.n.r) / tmp.n.r;
if (tmp2.n.r <= 0.0) return("Negative");
x.type = 'R';
x.n.r = sqrt(tmp2.n.r);
tmp2.n.r = (sn.n.r * sy2.n.r - sy.n.r * sy.n.r) / tmp.n.r;
if (tmp2.n.r <= 0.0) return("Negative");
y.type = 'R';
y.n.r = sqrt(tmp2.n.r);
break;
case CM_SF:
if (cmdnum < 1 || cmdnum > MAXFLAG) return("illegal flag");
num = cmdnum - 1;
m.flags[num >> 4] |= 1 << (num & 0xF);
break;
case CM_SIGN:
if (x.n.r < 0) x.n.r = -1.0;
if (x.n.r > 0) x.n.r = 1.0;
break;
case CM_SIN:
U_FromTrig(&x);
x.n.r = sin(x.n.r);
break;
case CM_SQ:
x.n.r *= x.n.r;
break;
case CM_SQRT:
if (x.n.r <= 0.0) return("Negative or Zero");
x.n.r = sqrt(x.n.r);
break;
case CM_STD:
U_FlSet(FL_DISPFMT, FLV_STD);
break;
case CM_STO:
y = *cmdreg;
U_Dispatch(cmdcmd);
*cmdreg = x;
break;
case CM_SUB:
if (x.type == 'B' && y.type == 'B') {
x.n.b = y.n.b - x.n.b;
x.n.b &= bin_mask;
}
else {
U_ToReal(&x);
U_ToReal(&y);
x.type = 'R';
x.n.r = y.n.r - x.n.r;
}
break;
case CM_SUMADD:
num = U_FlGet(FL_SUMBASE);
U_ToReal(&m.r[num + SUMN]);
U_ToReal(&m.r[num + SUMX]);
U_ToReal(&m.r[num + SUMX2]);
U_ToReal(&m.r[num + SUMY]);
U_ToReal(&m.r[num + SUMY2]);
U_ToReal(&m.r[num + SUMXY]);
m.r[num + SUMN].n.r += 1;
m.r[num + SUMX].n.r += x.n.r;
m.r[num + SUMX2].n.r += x.n.r * x.n.r;
m.r[num + SUMY].n.r += y.n.r;
m.r[num + SUMY2].n.r += y.n.r * y.n.r;
m.r[num + SUMXY].n.r += x.n.r * y.n.r;
x.n.r = m.r[num + SUMN].n.r;
break;
case CM_SUMGET:
x.type = 'R';
x.n.r = U_FlGet(FL_SUMBASE);
break;
case CM_SUMSET:
num = cmdreg - &m.r[0];
if (num < 0 || num > REGCOUNT - NUMSUM)
return("Out of Range");
U_FlSet(FL_SUMBASE, num);
break;
case CM_SUMSUB:
num = U_FlGet(FL_SUMBASE);
U_ToReal(&m.r[num + SUMN]);
U_ToReal(&m.r[num + SUMX]);
U_ToReal(&m.r[num + SUMX2]);
U_ToReal(&m.r[num + SUMY]);
U_ToReal(&m.r[num + SUMY2]);
U_ToReal(&m.r[num + SUMXY]);
m.r[num + SUMN].n.r -= 1;
m.r[num + SUMX].n.r -= x.n.r;
m.r[num + SUMX2].n.r -= x.n.r * x.n.r;
m.r[num + SUMY].n.r -= y.n.r;
m.r[num + SUMY2].n.r -= y.n.r * y.n.r;
m.r[num + SUMXY].n.r -= x.n.r * y.n.r;
x.n.r = m.r[num + SUMN].n.r;
break;
case CM_SWAP:
tmp = y;
y = x;
x = tmp;
break;
case CM_SWAPR:
tmp = x;
x = *cmdreg;
*cmdreg = tmp;
break;
case CM_TAN:
U_FromTrig(&x);
x.n.r = tan(x.n.r);
break;
case CM_TENX:
x.n.r = pow(10.0, x.n.r);
break;
case CM_TIME:
DNow(&t);
xsprintf(buf, "%d.%02d%02d", t.tm_hour, t.tm_min, t.tm_sec);
sscanf(buf, "%lf", &x.n.r);
x.type = 'R';
break;
case CM_TRACEOFF:
m.trace_mode = FALSE;
break;
case CM_TRACEON:
m.trace_mode = TRUE;
break;
case CM_WSIZE:
if (x.n.b < 0 || x.n.b > BINSIZE) return("Out of Range");
U_FlSet(FL_WSIZE, (int)x.n.b);
if (x.n.b == BINSIZE)
bin_mask = ~0;
else bin_mask = (1 << x.n.b) - 1;
break;
case CM_WSIZEQ:
x.type = 'B';
x.n.b = U_FlGet(FL_WSIZE);
break;
case CM_X360:
U_FlSet(FL_CALMODE, FLV_360);
break;
case CM_X365:
U_FlSet(FL_CALMODE, FLV_365);
break;
case CM_XACTUAL:
U_FlSet(FL_CALMODE, FLV_ACT);
break;
case CM_XCAL:
U_ToTM(&t, x.n.r);
DXCal(&t);
DIncrDisplay();
break;
case CM_XCALD:
DMove(x.n.b);
DIncrDisplay();
break;
case CM_XEQ:
bptr = BBufFind(cmdrest);
if (bptr == NULL) return("unknown program");
KFromBuf(bptr);
break;
case CM_XOR:
x.n.b ^= y.n.b;
x.n.b &= bin_mask;
break;
case CM_XRND:
num = x.n.b;
for (cnt = 0; cnt < num; cnt++) y.n.r *= 10.0;
y.n.r += (y.n.r > 0) ? 0.5 : -0.5;
tmp.n.b = y.n.r;
x.n.r = tmp.n.b;
for (cnt = 0; cnt < num; cnt++) x.n.r /= 10.0;
x.type = 'R';
break;
case CM_XROOT:
if (y.n.r < 0.0 || (y.n.r == 0.0 && x.n.r <= 0.0))
return("Negative");
x.n.r = pow(y.n.r, 1.0 / x.n.r);
break;
}
return(NULL);
}
/* ------------------------------------------------------------ */
/* Return a pointer to the command structure for the specified
command. */
struct command *
U_FindCmd(cmd)
enum CMDS cmd;
{
struct command *cptr;
for (cptr = commands; cptr < &commands[NUMCMDS]; cptr++) {
if (cmd == cptr->cmd) return(cptr);
}
return(NULL);
}
/* ------------------------------------------------------------ */
/* Return the value of the specified flag. */
int
U_FlGet(f)
enum FLGS f;
{
struct flag *fptr = &flags[(int)f];
return((m.flags[fptr->index] >> fptr->shift) & fptr->mask);
}
/* ------------------------------------------------------------ */
/* Set the specified flag to the supplied value. */
void
U_FlSet(f, v)
enum FLGS f;
int v;
{
struct flag *fptr = &flags[(int)f];
v = (v & fptr->mask) << fptr->shift;
m.flags[fptr->index] &= ~(fptr->mask << fptr->shift);
m.flags[fptr->index] |= v;
}
/* ------------------------------------------------------------ */
/* Return a pointer to a static buffer that contains a formatted
version of the number. */
char *
U_Fmt(nptr)
struct number *nptr;
{
int mode = U_FlGet(FL_BINMODE);
int cnt;
FLAG iscomma = U_FlGet(FL_RADIX) == 0;
char *cptr;
char *cptr2;
if (nptr->type == 'B') {
switch (mode) {
case FLV_BIN:
*fmt_buf = '#';
U_FmtBin(&fmt_buf[1], nptr->n.b, TRUE);
strcat(fmt_buf, "b");
break;
case FLV_OCT:
xsprintf(fmt_buf, "#%oo", nptr->n.b);
break;
case FLV_DEC:
xsprintf(fmt_buf, "#%ud", nptr->n.b);
break;
case FLV_HEX:
xsprintf(fmt_buf, "#%xh", nptr->n.b);
break;
}
}
else {
sprintf(fmt_buf, "%.9lg", nptr->n.r);
/* handle comma */
if (iscomma) {
for (cptr = fmt_buf; *cptr != NUL; cptr++) {
if (*cptr == '.') *cptr = ',';
}
}
/* handle digit separator */
if (U_FlGet(FL_DIGGRP) == 1) {
cptr2 = fmt_buf;
if (*cptr2 == '-') cptr2++;
cnt = 0;
for (cptr = cptr2; xisdigit(*cptr); cptr++, cnt++) ;
while (cnt > 3) {
cptr -= 3;
memmove(cptr + 1, cptr, strlen(cptr) + 1);
*cptr = iscomma ? '.' : ',';
cnt -= 3;
}
}
}
return(fmt_buf);
}
/* ------------------------------------------------------------ */
/* Print out a binary integer. */
char *
U_FmtBin(buf, value, first)
char *buf;
int value;
FLAG first;
{
if (value >= 2) buf = U_FmtBin(buf, value / 2, FALSE);
if (value == 0 && first)
*buf++ = '0';
else *buf++ = (value % 2) + '0';
*buf = NUL;
return(buf);
}
/* ------------------------------------------------------------ */
/* Convert the number in the current trig mode to radians. */
void
U_FromTrig(nptr)
struct number *nptr;
{
int mode = U_FlGet(FL_TRIGMODE);
if (mode == FLV_DEG) nptr->n.r *= PI / 180.00;
else if (mode == FLV_GRD) nptr->n.r *= PI / 200.00;
}
/* ------------------------------------------------------------ */
/* Add the two times in hms format. */
double
U_HMSAdd(hms1, hms2)
double hms1;
double hms2;
{
double hr1;
double hr2;
hr1 = U_ToHR(hms1);
hr2 = U_ToHR(hms2);
return(U_ToHMS(hr1 + hr2));
}
/* ------------------------------------------------------------ */
/* Input the next command. */
FLAG
U_In()
{
int chr;
int amt;
int cnt;
int base;
char buf[BIGBUFFSIZE];
char *cptr;
char *cptr2;
FLAG isdone = FALSE;
FLAG iscomma;
cmdptr = NULL;
*input = NUL;
if (pushedcmd != CM_NULL) {
cmdptr = U_FindCmd(pushedcmd);
pushedcmd = CM_NULL;
return;
}
while (!isdone) {
U_Status();
amt = strlen(input);
chr = KGetChar();
#if defined(MSDOS)
if (chr >= 256) { /* function key */
chr -= 256;
if (c.g.special == 'J' && chr >= 133 && chr <= 141) {
TabDispatch(chr + 256, 0);
if (doabort) exit = 'N';
return;
}
switch (chr) {
case 59: /* F1 */
pushedcmd = CM_HELP;
isdone = TRUE;
break;
case 67: /* F9 */
case 38: /* Alt-L */
chr = '-';
goto chs;
/*break;*/
case 93: /* Shift-F10 */
exit = 'N';
MExit();
return;
/*break;*/
case 48: /* Alt-B */
pushedcmd = CM_LASTX;
isdone = TRUE;
break;
case 46: /* Alt-C */
pushedcmd = CM_SWAP;
isdone = TRUE;
break;
case 50: /* Alt-M */
xstrcpy(input, "RCL");
amt = strlen(input);
break;
case 49: /* Alt-N */
xstrcpy(input, "STO");
amt = strlen(input);
break;
case 47: /* Alt-V */
pushedcmd = CM_RDN;
isdone = TRUE;
break;
case 45: /* Alt-X */
pushedcmd = CM_INV;
isdone = TRUE;
break;
case 44: /* Alt-Z */
pushedcmd = CM_SQRT;
isdone = TRUE;
break;
default:
TBell();
return;
/*break;*/
}
continue;
}
#endif
if (!isdone) {
switch (chr) {
case KEYQUIT:
case KEYABORT:
case ESC:
case BEL:
case '$':
exit = 'N';
isdone = TRUE;
break;
case LF:
exit = 'Y';
isdone = TRUE;
break;
case BS:
case DEL:
if (*input != NUL) input[amt - 1] = NUL;
else {
cmdptr = U_FindCmd(CM_CLX);
isdone = TRUE;
}
break;
case SP:
case CR:
isdone = TRUE;
break;
case '%':
if (*input == '\'') goto accumulate;
pushedcmd = CM_PCT;
isdone = TRUE;
break;
case '*':
if (*input == '\'') goto accumulate;
pushedcmd = CM_MUL;
isdone = TRUE;
break;
case '+':
if (*input == '\'') goto accumulate;
pushedcmd = CM_ADD;
isdone = TRUE;
break;
case '-':
if (*input == '\'') goto accumulate;
pushedcmd = CM_SUB;
isdone = TRUE;
break;
case '/':
if (*input == '\'') goto accumulate;
pushedcmd = CM_DIV;
isdone = TRUE;
break;
case '^':
if (*input == '\'') goto accumulate;
pushedcmd = CM_PWR;
isdone = TRUE;
break;
case '\'':
if (*input == '\'') goto accumulate;
if (amt >= sizeof(input) - 1) {
input[amt - 1] = NUL;
TBell();
}
memmove(input + 1, input, amt + 1);
*input = '\'';
break;
case '`':
case '~':
chs:
if (*input == '\'') goto accumulate;
if (*input == NUL) {
cmdptr = U_FindCmd(CM_NEG);
isdone = TRUE;
}
else {
cptr = input + amt;
while (cptr > input &&
xtoupper(*cptr) != 'E' &&
*cptr != '-') cptr--;
if (*cptr == '-') {
xstrcpy(cptr, cptr + 1);
}
else {
if (amt >= sizeof(input) - 1) {
input[amt - 1] = NUL;
TBell();
}
if (xtoupper(*cptr) == 'E')
cptr++;
memmove(cptr + 1, cptr,
strlen(cptr) + 1);
*cptr = '-';
}
}
break;
default:
accumulate:
if (amt >= sizeof(input) - 1) {
input[amt - 1] = NUL;
TBell();
}
input[amt] = chr;
input[amt + 1] = NUL;
break;
}
}
}
if (*input == NUL || cmdptr != NULL) return;
if (*input == '\'') xstrcpy(input, input + 1);
/* check for binary numbers */
if (*input == '#') {
cnt = U_FlGet(FL_BINMODE);
if (cnt == FLV_BIN) base = 2;
else if (cnt == FLV_OCT) base = 8;
else if (cnt == FLV_DEC) base = 10;
else base = 16;
if (!SToN(&input[1], &x.n.b, base)) {
DError("Invalid binary number");
return;
}
x.n.b &= bin_mask;
x.type = 'B';
cmdptr = U_FindCmd(CM_NUM);
return;
}
/* try for real number */
/* handle radix mark, dig sep char, ~->- */
iscomma = U_FlGet(FL_RADIX) == 0;
for (cptr = input, cptr2 = buf; *cptr != NUL; cptr++) {
chr = *cptr;
if (chr == '~' || chr == '`') chr = '-';
else if (iscomma) {
if (chr == ',') chr = '.';
else if (chr == '.') continue;
}
else {
if (chr == ',') continue;
}
*cptr2++ = chr;
}
*cptr2 = NUL;
/* handle numbers that start with EEX */
cptr = buf;
if (*cptr == '-') cptr++;
if (xtoupper(*cptr) == 'E') {
memmove(cptr + 1, cptr, strlen(cptr) + 1);
*cptr = '1';
}
/* check for real number */
if (sscanf(buf, "%lf", &x.n.r) == 1) {
x.type = 'R';
cmdptr = U_FindCmd(CM_NUM);
return;
}
/* else command */
if (U_FlGet(FL_UPPREQ)) {
for (cmdptr = commands; cmdptr < &commands[NUMCMDS];
cmdptr++) {
if (cmdptr->desc[0] == SP) {
if (strcmp(input, cmdptr->name) == 0) break;
}
else {
if (strncmp(input, cmdptr->name,
strlen(cmdptr->name)) == 0) break;
}
}
}
else {
for (cmdptr = commands; cmdptr < &commands[NUMCMDS];
cmdptr++) {
if (cmdptr->desc[0] == SP) {
if (strequ(input, cmdptr->name)) break;
}
else {
if (strnequ(input, cmdptr->name,
strlen(cmdptr->name))) break;
}
}
}
if (cmdptr >= &commands[NUMCMDS]) {
DError("Unknown Command");
cmdptr = NULL;
return;
}
if (cmdptr->desc[0] == SP) return;
/* process suffix */
cptr = &input[strlen(cmdptr->name)];
cmdrest = cptr;
cmdcmd = CM_NULL;
cmdind = FALSE;
cmdnum = 0;
cmdreg = &m.r[0];
if (cmdptr->desc[0] == 'B') return;
/* is operator allowed? */
if (cmdptr->desc[0] == 'P') {
if (*cptr == '*') { cmdcmd = CM_MUL; cptr++; }
else if (*cptr == '+') { cmdcmd = CM_ADD; cptr++; }
else if (*cptr == '-') { cmdcmd = CM_SUB; cptr++; }
else if (*cptr == '/') { cmdcmd = CM_DIV; cptr++; }
else if (*cptr == '^') { cmdcmd = CM_PWR; cptr++; }
}
/* is indirect allowed? */
if (cmdptr->desc[0] == 'R' || cmdptr->desc[0] == 'P') {
if (*cptr == '.') {
cmdind = TRUE;
cptr++;
}
else if (U_FlGet(FL_UPPREQ) ?
strncmp(cptr, "IND", 3) == 0 :
strnequ(cptr, "IND", 3)) {
cmdind = TRUE;
cptr += 3;
}
/* check for register name */
if (xisalpha(*cptr)) {
if (*(cptr + 1) != NUL) {
DError("Unknown Register");
cmdptr = NULL;
return;
}
if (!U_FlGet(FL_UPPREQ)) *cptr = xtoupper(*cptr);
if (*cptr == 'X') { cmdreg = &m.r[X]; cmdnum = X; }
else if (*cptr == 'Y') {cmdreg = &m.r[Y]; cmdnum = Y; }
else if (*cptr == 'Z') {cmdreg = &m.r[Z]; cmdnum = Z; }
else if (*cptr == 'T') {cmdreg = &m.r[T]; cmdnum = T; }
else if (*cptr == 'L') {cmdreg = &m.r[L]; cmdnum = L; }
else {
DError("Unknown Register");
cmdptr = NULL;
return;
}
return;
}
}
/* number is always allowed by the time that you get here */
if (cmdptr->cmd == CM_RCL && *cptr == '~' || *cptr == '-') {
cmdnum = -78;
return;
}
if (!SToN(cptr, &cmdnum, 10)) {
DError("Unknown Register");
cmdptr = NULL;
return;
}
if (cmdnum < 0 || cmdnum >= REGCOUNT) {
DError("Unknown Register");
cmdptr = NULL;
return;
}
cmdreg = &m.r[cmdnum];
}
/* ------------------------------------------------------------ */
/* Ask for a file name and load memory from that file. */
void
U_Load()
{
struct memory m2;
int fd;
if (KGetStr("Load memory from file", fname, sizeof(fname)) != 'Y') return;
#if defined(MSDOS)
#define O_RDONLY 0 /* dummy */
#endif
if ((fd = open(fname, O_RDONLY, 0)) < 0) {
DError("Cannot open file.");
return;
}
if (read(fd, (char *)&m2, sizeof(m2)) != sizeof(m2))
DError("Cannot read file.");
else m = m2;
close(fd);
}
/* ------------------------------------------------------------ */
/* Save the configuration information. Print a message on error. */
void
U_Save()
{
int fd;
if (KGetStr("Save memory to file", fname, sizeof(fname)) != 'Y') return;
#if defined(MSDOS)
if ((fd = creat(cbuf->fname)) < 0) {
#endif
#if defined(UNIX)
if ((fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
#endif
DError("Cannot create file.");
return;
}
if (write(fd, (char *)&m, sizeof(m)) != sizeof(m))
DError("Cannot write file.");
close(fd);
}
/* ------------------------------------------------------------ */
/* Display the calculator status line */
void
U_Status()
{
char buf[4 * LINEBUFFSIZE];
char *cptr = buf;
int amt;
if (KIsKey() == 'Y') return;
xsprintf(cptr, "L)%s ", U_Fmt(&m.r[L]));
cptr += strlen(cptr);
xsprintf(cptr, "T)%s ", U_Fmt(&m.r[T]));
cptr += strlen(cptr);
xsprintf(cptr, "Z)%s ", U_Fmt(&m.r[Z]));
cptr += strlen(cptr);
xsprintf(cptr, "Y)%s ", U_Fmt(&m.r[Y]));
cptr += strlen(cptr);
xsprintf(cptr, "X)%s ", U_Fmt(&m.r[X]));
cptr += strlen(cptr);
if (TMaxCol() >= 80)
amt = (TMaxCol() - WORKSIZE) - (cptr - buf);
else amt = (TMaxCol() - 12) - (cptr - buf);
if (amt > 0) {
while (amt-- > 0) *cptr++ = SP;
*cptr = NUL;
}
else {
xstrcpy(buf, buf - amt);
cptr = buf + strlen(buf);
}
*cptr++ = '>';
*cptr = NUL;
xstrcpy(cptr, input);
DEcho(buf);
TSetPoint(TMaxRow() - 1, strlen(buf));
}
/* ------------------------------------------------------------ */
/* Convert the number to a binary number, if required. */
void
U_ToBin(nptr)
struct number *nptr;
{
double r;
if (nptr->type == 'R') {
r = nptr->n.r;
nptr->n.b = r;
nptr->type = 'B';
}
}
/* ------------------------------------------------------------ */
/* Convert the date to a real number according to the current date
format. */
double
U_ToDate(tptr)
struct tm *tptr;
{
double tmp;
double i;
double f;
if (U_FlGet(FL_DMYDATE)) {
i = tptr->tm_mday;
f = tptr->tm_mon + 1;
}
else {
i = tptr->tm_mon + 1;
f = tptr->tm_mday;
}
tmp = tptr->tm_year;
tmp /= 1000000.;
tmp += f / 100.;
tmp += i;
return(tmp);
}
/* ------------------------------------------------------------ */
/* Convert a time in decimal hours form to HH.MMSSss. */
double
U_ToHMS(hr)
double hr;
{
double tmp;
FLAG isneg = FALSE;
int h;
int m;
int s;
if (hr < 0.0) {
isneg = TRUE;
hr = -hr;
}
h = hr;
hr -= floor(hr);
hr *= 60.;
m = hr;
hr -= floor(hr);
hr *= 6000.;
s = hr;
/* round hundreths of seconds off */
s += 50;
s /= 100;
tmp = h;
tmp += (double)m / 100.;
tmp += (double)s / 10000.;
if (isneg) tmp = -tmp;
return(tmp);
}
/* ------------------------------------------------------------ */
/* Convert a time in HH.MMSSss form to decimal hours. */
double
U_ToHR(hms)
double hms;
{
double tmp;
FLAG isneg = FALSE;
int h;
int m;
int s;
if (hms < 0.0) {
isneg = TRUE;
hms = -hms;
}
h = hms;
hms -= floor(hms);
hms *= 100.;
m = hms;
hms -= floor(hms);
hms *= 10000.;
s = hms;
tmp = h;
tmp += (double)m / 60.;
tmp += (double)s / 360000.;
if (isneg) tmp = -tmp;
return(tmp);
}
/* ------------------------------------------------------------ */
/* Convert the number to a real number, if required. */
void
U_ToReal(nptr)
struct number *nptr;
{
int b;
if (nptr->type == 'B') {
b = nptr->n.b;
nptr->n.r = b;
nptr->type = 'R';
}
}
/* ------------------------------------------------------------ */
/* Convert the real number date to struct tm according to the current
date format. */
void
U_ToTM(tptr, date)
struct tm *tptr;
double date;
{
double d;
int i;
int f;
memset((char *)tptr, NUL, sizeof(*tptr));
i = date;
date *= 100.;
f = date;
f %= 100;
date -= floor(date);
tptr->tm_year = date * 10000. + .5;
if (U_FlGet(FL_DMYDATE)) {
tptr->tm_mday = i;
tptr->tm_mon = f - 1;
}
else {
tptr->tm_mon = i - 1;
tptr->tm_mday = f;
}
}
/* ------------------------------------------------------------ */
/* Convert the number (in radians) to the current trig mode. */
void
U_ToTrig(nptr)
struct number *nptr;
{
int mode = U_FlGet(FL_TRIGMODE);
if (mode == FLV_DEG) nptr->n.r *= 180.0 / PI;
else if (mode == FLV_GRD) nptr->n.r *= 200.0 / PI;
}
/* ------------------------------------------------------------ */
/* Print the pre-execution trace information. */
void
U_Trace1()
{
char buf[LINEBUFFSIZE];
if (!FMakeSys(SYS_TRACE, FALSE)) return;
if (cmdptr->desc[9] == 'R' && cmdreg != NULL) {
xsprintf(buf, "register %d was %s\n", cmdreg - &m.r[0],
U_Fmt(cmdreg));
BInsStr(buf);
}
}
/* ------------------------------------------------------------ */
/* Print the post-execution trace information. */
void
U_Trace2(retval)
char *retval;
{
char buf[LINEBUFFSIZE];
int num;
if (!FMakeSys(SYS_TRACE, FALSE)) return;
BInsStr(cmdptr->name);
if (cmdptr->desc[0] != SP) {
if (cmdcmd != CM_NULL) BInsStr(U_FindCmd(cmdcmd)->name);
if (cmdind) BInsChar('.');
xsprintf(buf, "%d", cmdnum);
BInsStr(buf);
}
BInsStr(": ");
if (retval != NULL) {
xsprintf(buf, "Error: %s\n", retval);
BInsStr(buf);
}
xsprintf(buf, "L)%s ", U_Fmt(&m.r[L]));
BInsStr(buf);
xsprintf(buf, "T)%s ", U_Fmt(&m.r[T]));
BInsStr(buf);
xsprintf(buf, "Z)%s ", U_Fmt(&m.r[Z]));
BInsStr(buf);
xsprintf(buf, "Y)%s ", U_Fmt(&m.r[Y]));
BInsStr(buf);
xsprintf(buf, "X)%s\n", U_Fmt(&m.r[X]));
BInsStr(buf);
if (cmdptr->desc[9] == 'S') {
num = U_FlGet(FL_SUMBASE);
xsprintf(buf, "n\t%s\n", U_Fmt(&m.r[num + SUMN]));
BInsStr(buf);
xsprintf(buf, "x\t%s\n", U_Fmt(&m.r[num + SUMX]));
BInsStr(buf);
xsprintf(buf, "x^2\t%s\n", U_Fmt(&m.r[num + SUMX2]));
BInsStr(buf);
xsprintf(buf, "y\t%s\n", U_Fmt(&m.r[num + SUMY]));
BInsStr(buf);
xsprintf(buf, "y^2\t%s\n", U_Fmt(&m.r[num + SUMY2]));
BInsStr(buf);
xsprintf(buf, "x*y\t%s\n", U_Fmt(&m.r[num + SUMXY]));
BInsStr(buf);
}
else if (cmdptr->desc[9] == 'R') {
xsprintf(buf, "register %d is %s\n", cmdreg - &m.r[0],
U_Fmt(cmdreg));
BInsStr(buf);
}
DIncrDisplay();
}
/* ------------------------------------------------------------ */
/* View interpreted calculator memory. */
void
U_View()
{
char buf[LINEBUFFSIZE];
struct flag *fptr;
int cnt;
if (!FMakeSys(SYS_CALC, TRUE)) return;
BInsStr("Stack:\n");
xsprintf(buf, "X\t%s\n", U_Fmt(&m.r[X]));
BInsStr(buf);
xsprintf(buf, "Y\t%s\n", U_Fmt(&m.r[Y]));
BInsStr(buf);
xsprintf(buf, "Z\t%s\n", U_Fmt(&m.r[Z]));
BInsStr(buf);
xsprintf(buf, "T\t%s\n", U_Fmt(&m.r[T]));
BInsStr(buf);
xsprintf(buf, "L\t%s\n", U_Fmt(&m.r[L]));
BInsStr(buf);
BInsStr(
"\nFlags (start/bits, value, description (NS = \"not supported\"):\n");
for (fptr = flags; fptr < &flags[(int) FL_LAST]; fptr++) {
xsprintf(buf, "%d/%d\t%d\t%s\n",
fptr->start,
fptr->bits,
U_FlGet(fptr - flags),
fptr->desc);
BInsStr(buf);
}
BInsStr("\nFlags (values):\n");
for (cnt = 0; cnt < NUMFLAGS; cnt++) {
xsprintf(buf, "%3d - %3d %04x\n",
cnt * 16 + 16,
cnt * 16 + 1,
m.flags[cnt]);
BInsStr(buf);
}
BInsStr("\nRegisters:\n");
for (cnt = 0; cnt < REGCOUNT; cnt++) {
xsprintf(buf, "R%02d\t%s\n", cnt, U_Fmt(&m.r[cnt]));
BInsStr(buf);
}
BMoveToStart();
DIncrDisplay();
}
/* ------------------------------------------------------------ */
/* View interpreted summation memory. */
void
U_ViewSum()
{
char buf[LINEBUFFSIZE];
int num;
if (!FMakeSys(SYS_CALC, TRUE)) return;
num = U_FlGet(FL_SUMBASE);
xsprintf(buf, "n\t%s\n", U_Fmt(&m.r[num + SUMN]));
BInsStr(buf);
xsprintf(buf, "x\t%s\n", U_Fmt(&m.r[num + SUMX]));
BInsStr(buf);
xsprintf(buf, "x^2\t%s\n", U_Fmt(&m.r[num + SUMX2]));
BInsStr(buf);
xsprintf(buf, "y\t%s\n", U_Fmt(&m.r[num + SUMY]));
BInsStr(buf);
xsprintf(buf, "y^2\t%s\n", U_Fmt(&m.r[num + SUMY2]));
BInsStr(buf);
xsprintf(buf, "x*y\t%s\n", U_Fmt(&m.r[num + SUMXY]));
BInsStr(buf);
BMoveToStart();
DIncrDisplay();
}
/* end of CALC.C -- RPN Calculator */